#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "mailbox.h"
#include "esp_ipc.h"

#define TAG "MAILBOX"

// IPC传输结构（必须放在SPIRAM）
typedef struct {
    app_msg_t *msg;         // 消息指针
    QueueHandle_t target_queue; // 目标队列
} __attribute__((packed)) ipc_transfer_t;

// 全局注册表
static mailbox_entry_t task_registry[MAX_REGISTERED_TASKS] = {0};
static portMUX_TYPE registry_lock = portMUX_INITIALIZER_UNLOCKED;

// 注册当前任务到邮箱系统
esp_err_t mailbox_register_current_task()
{
    TaskHandle_t current_task = xTaskGetCurrentTaskHandle();
    
    portENTER_CRITICAL(&registry_lock);
    for (int i = 0; i < MAX_REGISTERED_TASKS; i++) {
        if (task_registry[i].task_handle == NULL) {
            task_registry[i].task_handle = current_task;
            task_registry[i].core_id = xPortGetCoreID();
            task_registry[i].msg_queue = xQueueCreate(MBOX_QUEUE_MAX_SIZE, sizeof(app_msg_t*));
            
            portEXIT_CRITICAL(&registry_lock);
            ESP_LOGI(TAG, "Task %p registered on core %d", current_task, task_registry[i].core_id);
            return ESP_OK;
        }
    }
    portEXIT_CRITICAL(&registry_lock);
    return ESP_ERR_NO_MEM;
}

// 注销任务邮箱
void mailbox_unregister_task(TaskHandle_t task)
{
    portENTER_CRITICAL(&registry_lock);
    for (int i = 0; i < MAX_REGISTERED_TASKS; i++) {
        if (task_registry[i].task_handle == task) {
            vQueueDelete(task_registry[i].msg_queue);
            memset(&task_registry[i], 0, sizeof(mailbox_entry_t));
            break;
        }
    }
    portEXIT_CRITICAL(&registry_lock);
}

// 查找目标任务的邮箱信息
mailbox_entry_t* find_mailbox_entry(TaskHandle_t target)
{
    portENTER_CRITICAL(&registry_lock);
    for (int i = 0; i < MAX_REGISTERED_TASKS; i++) {
        if (task_registry[i].task_handle == target) {
            portEXIT_CRITICAL(&registry_lock);
            return &task_registry[i];
        }
    }
    portEXIT_CRITICAL(&registry_lock);
    return NULL;
}

#if 0
// IPC服务函数（在目标核心执行）
static void ipc_message_handler(void *arg)
{
    ipc_transfer_t *xfer = (ipc_transfer_t*)arg;
    
    // 将消息投递到目标队列
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(xfer->target_queue, &xfer->msg, &xHigherPriorityTaskWoken);
    
    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR();
    }
    
    // 释放传输结构（不释放消息内容）
    free(xfer);
}

// 跨核发送实现
static esp_err_t ipc_send_cross_core(app_msg_t *msg, mailbox_entry_t *target, TickType_t timeout)
{
    // 1. 分配SPIRAM传输结构
    ipc_transfer_t *xfer = heap_caps_malloc(sizeof(ipc_transfer_t), MALLOC_CAP_SPIRAM);
    if (!xfer) {
        return ESP_ERR_NO_MEM;
    }
    
    // 2. 初始化传输结构
    xfer->msg = msg;
    xfer->target_queue = target->msg_queue;

    // 3. 执行跨核调用
    esp_err_t ret = esp_ipc_call(target->core_id, ipc_message_handler, xfer);
    
    // 4. 错误处理
    if(ret != ESP_OK){
        ESP_LOGE(TAG, "IPC send failed: 0x%x", ret);
        free(msg);
        free(xfer);
    }
    return ret;
}
#endif

// 核心发送函数
esp_err_t mailbox_send_to_task(app_msg_t *msg, TaskHandle_t target, TickType_t timeout)
{
    // 1. 验证目标状态
    mailbox_entry_t *target_entry = find_mailbox_entry(target);
    if (!target_entry || !target_entry->msg_queue) {
        ESP_LOGE(TAG, "Target task %p not registered", target);
        return ESP_ERR_INVALID_ARG;
    }

    msg->target = xTaskGetCurrentTaskHandle(); // 设置响应目标为发送者

    // 2. 深拷贝消息
    app_msg_t *msg_copy = malloc(sizeof(app_msg_t));
    memcpy(msg_copy, msg, sizeof(app_msg_t));
    
    // 3. 处理指针数据
    if ((msg->reserve == RESERVE_PTR) && msg->ptr) {
        void *data_copy = heap_caps_malloc(msg->data_size, MALLOC_CAP_SPIRAM);
        memcpy(data_copy, msg->ptr, msg->data_size);
        msg_copy->ptr = data_copy;
    }

    return xQueueSend(target_entry->msg_queue, &msg_copy, timeout) == pdTRUE ? ESP_OK : ESP_FAIL;

#if 0
    // 4. 同核直接发送
    if (target_entry->core_id == xPortGetCoreID()) {
        return xQueueSend(target_entry->msg_queue, &msg_copy, timeout);
    }
    
    // 5. 跨核发送流程
    return ipc_send_cross_core(msg_copy, target_entry, timeout);
#endif
}

// 广播消息
void mailbox_broadcast(app_msg_t *msg, TickType_t timeout)
{
    msg->target = xTaskGetCurrentTaskHandle(); // 设置响应目标为发送者

    portENTER_CRITICAL(&registry_lock);
    for (int i = 0; i < MAX_REGISTERED_TASKS; i++) {
        if (task_registry[i].task_handle) {
            app_msg_t *copy = malloc(sizeof(app_msg_t));
            memcpy(copy, msg, sizeof(app_msg_t));
            xQueueSend(task_registry[i].msg_queue, &copy, timeout);
        }
    }
    portEXIT_CRITICAL(&registry_lock);
}

// 同步RPC调用
esp_err_t mailbox_rpc_call(app_msg_t *msg, TaskHandle_t target, app_msg_t **response, TickType_t timeout)
{
    // 动态创建消息副本
    app_msg_t *msg_copy = malloc(sizeof(app_msg_t));
    memcpy(msg_copy, msg, sizeof(app_msg_t));
    
    // 创建信号量
    SemaphoreHandle_t sem = xSemaphoreCreateBinary();
    msg_copy->sync_sem = sem;

    // 发送消息
    esp_err_t ret = mailbox_send_to_task(msg_copy, target, timeout);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "RPC send failed[%d]: %s (target: %p)", ret, esp_err_to_name(ret), target);
        if ((msg_copy->reserve == RESERVE_PTR) && msg_copy->ptr) {
            free(msg_copy->ptr);
        }
        free(msg_copy);
        vSemaphoreDelete(sem);
        return ret;
    }

    // 等待响应
    if (xSemaphoreTake(sem, timeout) == pdTRUE) {
        if (response) {
            *response = msg_copy->response;
        }
    } else {
        ESP_LOGE(TAG, "RPC timeout (target: %p)", target);
        ret = ESP_ERR_TIMEOUT;
    }

    // 清理资源
    if ((msg_copy->reserve == RESERVE_PTR) && msg_copy->ptr) {
        free(msg_copy->ptr);
    }
    free(msg_copy);
    vSemaphoreDelete(sem);
    return ret;
}

void mailbox_response_or_free(app_msg_t *msg)
{
    if (msg->sync_sem) {
        xSemaphoreGive(msg->sync_sem);
        msg->sync_sem = NULL;
    } else if ((msg->reserve == RESERVE_PTR) && msg->ptr) {
        free(msg->ptr);
    }
    free(msg);
}
